﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Velocity4Net.Ctx;
using Velocity4Net.Errors;
using System.IO;
using Velocity4Net.Runtime.Parse.AST;
using Velocity4Net.Runtime.Logging;

namespace Velocity4Net.Runtime.Directives
{
    /**
     * Directive that puts an unrendered AST block in the context
     * under the specified key, postponing rendering until the
     * reference is used and rendered.
     *
     * @author Andrew Tetlaw
     * @author Nathan Bubna
     * @version $Id: Define.java 686842 2008-08-18 18:29:31Z nbubna $
     */
    public class Define : Block
    {
        /**
         * Return name of this directive.
         */
        public override String Name
        {
            get
            {
                return "define";
            }
            set { }
        }

        /**
         *  simple init - get the key
         */
        public override void Init(RuntimeServices rs, InternalContextAdapter context, INode node)
        {
            base.Init(rs, context, node);

            // the first child is the block name (key), the second child is the block AST body
            if (node.jjtGetNumChildren() != 2)
            {
                throw new VelocityException("parameter missing: block name at "
                     + Log.formatFileString(this));
            }

            /*
             * first token is the name of the block. We don't even check the format,
             * just assume it looks like this: $block_name. Should we check if it has
             * a '$' or not?
             */
            key = node.jjtGetChild(0).FirstToken.image.Substring(1);

            /*
             * default max depth of two is used because intentional recursion is
             * unlikely and discouraged, so make unintentional ones end fast
             */
            maxDepth = rs.GetInt(RuntimeConstants.DEFINE_DIRECTIVE_MAXDEPTH, 2);
        }

        /**
         * directive.render() simply makes an instance of the Block inner class
         * and places it into the context as indicated.
         */
        public override bool Render(InternalContextAdapter context, TextWriter writer, INode node)
        {
            /* put a Block.Reference instance into the context,
             * using the user-defined key, for later inline rendering.
             */
            context.Put(key, new Reference(context, this));
            return true;
        }

    }
}
